import { PageManager } from '../../../../lib/abstract/page_manager'
import { DocumentManager } from '../../../../lib/document_manager'
import { LOCAL_STORAGE_KEYS, logger, SettingsStyleId } from '../../../../types/constants'
import { SYMBOLS } from '../../../../types/interfaces'
import { BASE_LOADING_STYLES, LOADING_THEMES, LoadingThemeType } from './types'

export class LoadingThemeService {
  // @Decorators.Identity
  private readonly name: string = 'LoadingThemeService'
  // @Decorators.PublicState
  private static hasInitialized: boolean = false // 初始化标志
  private static instance: LoadingThemeService
  // @Decorators.Dependency
  private readonly documentManager: DocumentManager = DocumentManager.getInstance()
  private readonly cssStyleId: string = SettingsStyleId.LoadingThemeQuick
  // @Decorators.Config
  // 进度条是否显示文字
  private readonly enableProgressText: boolean = false
  // 进度条文字
  private readonly LOAD_PHRASES: { progress: number, text: string }[] = [
    { progress: 0, text: `服务启动中 ${SYMBOLS.OTHERS.ROCKET}` },
    { progress: 50, text: `马上就好 ${SYMBOLS.UI.BULLSEYE}` },
  ]

  // @Decorators.Core
  private removalTimeout?: number
  private readonly LOADING_TIMEOUT: number = 1500 // 超时时间（单位毫秒）
  // @Decorators.UIElement
  private progressElement: HTMLElement | null = null
  private progressTextElement: HTMLElement | null = null
  // @Decorators.TemporaryState
  private isCompleted: boolean = false
  private isForceCompleted: boolean = false

  constructor() {
    if (LoadingThemeService.hasInitialized)
      return

    this.setupEventListeners()
    const theme = this.getLoadingTheme()

    this.createStyleTag(theme)
    this.initLoading(theme)

    LoadingThemeService.hasInitialized = true
  }

  get loadingElement(): HTMLElement | null {
    return document.getElementById('loading')
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): LoadingThemeService {
    if (!LoadingThemeService.instance) {
      LoadingThemeService.instance = new LoadingThemeService()
    }
    return LoadingThemeService.instance
  }

  getLoadingTheme(): LoadingThemeType {
    const storageData = localStorage.getItem(LOCAL_STORAGE_KEYS.LoadingTheme) || ''
    return storageData.length !== 0 && Object.values(LoadingThemeType).includes(storageData as LoadingThemeType)
      ? storageData as LoadingThemeType
      : LoadingThemeType.TrinityRings
  }

  /**
   * 设置事件监听器
   */
  setupEventListeners(): void {
    // 使用标志位确保进度只增不减
    const domLoaded = false
    const fontsLoaded = false

    // DOM 就绪时标记
    document.addEventListener('DOMContentLoaded', () => {
      this.updateProgress(
        fontsLoaded ? 85 : 70, // 如果字体已加载则保持 85，否则设为 70
        'DOM 加载完成',
      )
    }, { once: true })

    // 页面完全加载时标记
    window.addEventListener('load', () => {
      this.isCompleted = true

      // this.updateProgress(100, '页面加载完成')
      // setTimeout(() => this.removeLoading(), 1000) // 给用户看到 100% 的机会
      this.removeLoading()
    }, { once: true })

    // 字体加载完成
    if (document.fonts) {
      document.fonts.ready.then(() => {
        this.updateProgress(
          domLoaded ? 85 : 70, // 如果 DOM 已加载则设为 85，否则保持 70
          '字体加载完成',
        )
      })
    }

    // 图片加载
    this.monitorCriticalImages()
  }

  /*
   * 检查加载完成状态
   */
  checkCompleteStatus(): boolean {
    return this.isCompleted || this.isForceCompleted
  }

  /**
   * 监控关键图片加载
   */
  monitorCriticalImages(): void {
    const criticalImages = document.querySelectorAll('img[loading="eager"]')

    if (criticalImages.length === 0)
      return

    let loadedCount = 0
    const total = criticalImages.length

    const updateImageProgress = () => {
      loadedCount++
      const progress = 70 + Math.floor((loadedCount / total) * 15)
      this.updateProgress(progress, `图片加载中 (${loadedCount}/${total})`)
    }

    criticalImages.forEach((img) => {
      const image = img as HTMLImageElement

      if (image.complete) {
        updateImageProgress()
      }
      else {
        image.addEventListener('load', updateImageProgress)
        image.addEventListener('error', updateImageProgress)
      }
    })
  }

  /**
   * 更新进度条和文本
   */
  updateProgress(progress: number, message?: string): void {
    if (this.checkCompleteStatus())
      return

    // 确保进度在 0-100 范围内
    const clampedProgress = Math.max(0, Math.min(100, progress))

    // 更新加载提示文本
    const loaderText = this.loadingElement?.querySelector('.loader-text')

    if (loaderText) {
      loaderText.textContent = this.getCurrentLoadText(clampedProgress)
    }

    // 更新进度文本元素
    if (this.progressElement) {
      this.progressElement.style.width = `${clampedProgress}%`
    }

    // 更新进度提示文本
    if (this.progressTextElement) {
      this.progressTextElement.textContent = message || `加载中... ${clampedProgress}%`

      // 根据进度改变文本颜色
      if (clampedProgress >= 80) {
        this.progressTextElement.style.color = '#4caf50' // 绿色表示接近完成
      }
      else if (clampedProgress >= 50) {
        this.progressTextElement.style.color = '#2196f3' // 蓝色表示中等进度
      }
      else {
        this.progressTextElement.style.color = '#f44336' // 红色表示初期
      }
    }

    // 动态调整加载动画速度
    if (this.loadingElement) {
      const loader = this.loadingElement.querySelector('.loader') as HTMLElement | null

      if (loader) {
        // 进度越快，动画速度越慢（接近完成时更平滑）
        const speed = 1 + (100 - clampedProgress) * 0.02
        loader.style.setProperty('--animation-speed', `${speed}s`)
      }
    }
  }

  initLoading(theme: LoadingThemeType): void {
    // 先移除已存在的加载元素
    this.removeLoading()

    this.documentManager.resetDocumentVisibilityStyles()
    this.documentManager.setDocumentOverflowStyles()

    const loadingElement = this.createLoadingElement(theme)
    document.documentElement.prepend(loadingElement) // 插入到 html 最前面

    // 获取进度相关元素
    this.progressElement = loadingElement.querySelector('.progress-bar-fill')
    this.progressTextElement = this.enableProgressText ? loadingElement.querySelector('.progress-text') : null

    // 初始显示动画
    loadingElement.style.opacity = '0'

    setTimeout(() => {
      loadingElement.style.transition = 'opacity 200ms'
      loadingElement.style.opacity = '1'
    }, 10) // 微延迟确保 CSS 应用

    this.setupLoadingBehavior(loadingElement)
  }

  private createLoadingElement(theme: LoadingThemeType): HTMLElement {
    const config = LOADING_THEMES[theme]
    const div = document.createElement('div')

    div.id = 'loading'
    div.innerHTML = `
      <div class="loader">
        ${config.htmlTemplate}
        <div class="loader-text">${this.getCurrentLoadText(0)}</div>
        <div class="progress-container">
          <div class="progress-bar">
            <div class="progress-bar-fill"></div>
          </div>
          ${this.enableProgressText ? '<div class="progress-text">（正在初始化...）</div>' : ''}
        </div>
      </div>
    `

    return div
  }

  /**
   * 获取当前进度对应的加载文本
   */
  private getCurrentLoadText(progress: number): string {
    const customPhrase = PageManager.getInstance().getLoadingPhrases()

    if (customPhrase)
      return customPhrase

    const phrase = [...this.LOAD_PHRASES]
      .reverse()
      .find(p => progress >= p.progress)

    return phrase?.text || '加载中...'
  }

  private setupLoadingBehavior(loadingElement: HTMLElement): void {
    // 初始渐隐效果
    setTimeout(() => {
      this.documentManager.resetBodyVisibilityStyles()

      loadingElement.style.transition = 'opacity 200ms'
      loadingElement.style.opacity = '0.8'
    }, 1000)

    // 超时强制移除
    this.removalTimeout = window.setTimeout(() => {
      if (loadingElement.isConnected) {
        this.isForceCompleted = true

        // this.updateProgress(100, '加载超时，强制完成')
        // setTimeout(() => this.removeLoading(), 1000) // 给用户看到 100% 的机会
        this.removeLoading()

        logger.debug(`[${this.name}] ${SYMBOLS.STATUS.WARNING} 强制移除加载动画（超时${this.LOADING_TIMEOUT / 1000}秒未完成）`)
      }
    }, this.LOADING_TIMEOUT)
  }

  removeLoading(): void {
    this.documentManager.applyLoadingStyles(false)

    clearTimeout(this.removalTimeout)

    this.loadingElement?.remove()
    this.progressElement = null
    this.progressTextElement = null
  }

  getLoadingStyles(theme: LoadingThemeType): string {
    return `
${BASE_LOADING_STYLES}
${LOADING_THEMES[theme].cssStyles}    
`
  }

  createStyleTag(theme: LoadingThemeType): void {
    // 立即插入内联样式（避免等待 CSS 加载）
    const style = document.createElement('style')

    style.textContent = this.getLoadingStyles(theme)
    style.id = this.cssStyleId

    document.head.prepend(style) // 插入到 head 最前面
  }
}
